﻿using System;
using Kaleida.ServiceMonitor.Framework.Responses;
using Kaleida.ServiceMonitor.Operations.ResponseHandlers;
using NUnit.Framework;

namespace Kaleida.UnitTests.Operations
{
    [TestFixture]
    public class MustBeLessThanTests
    {
        [Test]
        public void TestStringArgument()
        {
            var exception1 = Assert.Throws<InvalidOperationException>(() => new MustBeLessThan("123").ProcessResponse("122"));
            Assert.AreEqual("Cannot perform '122' < '123' with string values", exception1.Message);

            var exception2 = Assert.Throws<InvalidOperationException>(() => new MustBeLessThan("-123").ProcessResponse("-124"));
            Assert.AreEqual("Cannot perform '-124' < '-123' with string values", exception2.Message);

            var exception3 = Assert.Throws<InvalidOperationException>(() => new MustBeLessThan("abc").ProcessResponse("abb"));
            Assert.AreEqual("Cannot perform 'abb' < 'abc' with string values", exception3.Message);

            var exception4 = Assert.Throws<InvalidOperationException>(() => new MustBeLessThan("abc").ProcessResponse("Abb"));
            Assert.AreEqual("Cannot perform 'Abb' < 'abc' with string values", exception4.Message);
        }

        [Test]
        public void TestIntegerArgument()
        {
            Assert.AreEqual("122", new MustBeLessThan("123").ProcessResponse(122));
            Assert.AreEqual("-124", new MustBeLessThan("-123").ProcessResponse(-124));

            var exception1 = Assert.Throws<InvalidOperationException>(() => new MustBeLessThan("123.0").ProcessResponse(122));
            Assert.AreEqual("Cannot perform '122' < '123.0' with string values", exception1.Message);

            var exception2 = Assert.Throws<InvalidOperationException>(() => new MustBeLessThan("123").ProcessResponse(123));
            Assert.AreEqual("Expected response to be less than 123 but was 123", exception2.Message);

            var exception3 = Assert.Throws<InvalidOperationException>(() => new MustBeLessThan("123").ProcessResponse(124));
            Assert.AreEqual("Expected response to be less than 123 but was 124", exception3.Message);
        }

        [Test]
        public void TestDecimalArgument()
        {
            Assert.AreEqual("122.9", new MustBeLessThan("123").ProcessResponse(122.9m));
            Assert.AreEqual("-123.1", new MustBeLessThan("-123").ProcessResponse(-123.1m));
            Assert.AreEqual("122.9", new MustBeLessThan("123.0").ProcessResponse(122.9m));
            
            var exception1 = Assert.Throws<InvalidOperationException>(() => new MustBeLessThan("123.456").ProcessResponse(123.456m));
            Assert.AreEqual("Expected response to be less than 123.456 but was 123.456", exception1.Message);

            var exception2 = Assert.Throws<InvalidOperationException>(() => new MustBeLessThan("123.456").ProcessResponse(123.457m));
            Assert.AreEqual("Expected response to be less than 123.456 but was 123.457", exception2.Message);
        }

        [Test]
        public void TestTimeSpanArgument()
        {
            Assert.AreEqual("[00:02:30]", new MustBeLessThan("3m").ProcessResponse(TimeSpan.FromMinutes(2.5)));
            Assert.AreEqual("[00:00:00.044]", new MustBeLessThan("45ms").ProcessResponse(TimeSpan.FromMilliseconds(44)));
            Assert.AreEqual("[00:00:00.044]", new MustBeLessThan("45").ProcessResponse(TimeSpan.FromMilliseconds(44)));
            
            var exception1 = Assert.Throws<InvalidOperationException>(() => new MustBeLessThan("6s").ProcessResponse(TimeSpan.FromSeconds(6)));
            Assert.AreEqual("Expected response to be less than [00:00:06] but was [00:00:06]", exception1.Message);

            var exception2 = Assert.Throws<InvalidOperationException>(() => new MustBeLessThan("6s").ProcessResponse(TimeSpan.FromSeconds(7)));
            Assert.AreEqual("Expected response to be less than [00:00:06] but was [00:00:07]", exception2.Message);
        }

        [Test]
        public void TestTimedEventArgument()
        {
            Assert.AreEqual("Time Taken [00:02:30]", new MustBeLessThan("3m").ProcessResponse(new TimedEvent { TimeTaken = TimeSpan.FromMinutes(2.5) }));
            Assert.AreEqual("Time Taken [00:00:00.044]", new MustBeLessThan("45ms").ProcessResponse(new TimedEvent { TimeTaken = TimeSpan.FromMilliseconds(44) }));
            Assert.AreEqual("Time Taken [00:00:00.044]", new MustBeLessThan("45").ProcessResponse(new TimedEvent { TimeTaken = TimeSpan.FromMilliseconds(44) }));
            
            var exception1 = Assert.Throws<InvalidOperationException>(() => new MustBeLessThan("6s").ProcessResponse(new TimedEvent {TimeTaken = TimeSpan.FromSeconds(6)}));
            Assert.AreEqual("Expected response to be less than [00:00:06] but was [00:00:06]", exception1.Message);

            var exception2 = Assert.Throws<InvalidOperationException>(() => new MustBeLessThan("6s").ProcessResponse(new TimedEvent { TimeTaken = TimeSpan.FromSeconds(7) }));
            Assert.AreEqual("Expected response to be less than [00:00:06] but was [00:00:07]", exception2.Message);
        }

        private class TimedEvent : ITimedEvent
        {
            public TimeSpan TimeTaken { get; set; }
        }
    }
}
